package com.tydic.portal.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.NumberUtil;
import com.tydic.borderer.domain.BordererInfo;
import com.tydic.borderer.domain.vo.BordererInfoVo;
import com.tydic.borderer.domain.vo.MutualHelpOrganizationMemberVo;
import com.tydic.borderer.service.IBordererInfoService;
import com.tydic.borderer.service.IMutualHelpOrganizationService;
import com.tydic.common.core.constant.Constants;
import com.tydic.common.core.constant.GlobalConstants;
import com.tydic.common.core.domain.R;
import com.tydic.common.core.domain.model.LoginUser;
import com.tydic.common.core.enums.*;
import com.tydic.common.core.exception.ServiceException;
import com.tydic.common.core.exception.user.CaptchaException;
import com.tydic.common.core.exception.user.CaptchaExpireException;
import com.tydic.common.core.utils.MessageUtils;
import com.tydic.common.core.utils.StringUtils;
import com.tydic.common.core.validate.AddGroup;
import com.tydic.common.core.validate.EditGroup;
import com.tydic.common.core.validate.QueryGroup;
import com.tydic.common.mybatis.core.page.TableDataInfo;
import com.tydic.common.redis.utils.RedisUtils;
import com.tydic.common.satoken.utils.LoginHelper;
import com.tydic.common.web.core.BaseController;
import com.tydic.enterprise.domain.Enterprise;
import com.tydic.enterprise.service.IEnterpriseService;
import com.tydic.portal.domain.bo.ForgetPasswordBo;
import com.tydic.portal.domain.bo.PortalLoginBo;
import com.tydic.portal.domain.bo.RegisterUserBo;
import com.tydic.portal.domain.response.ManageUserInfoResponse;
import com.tydic.portal.domain.vo.PortalLoginVo;
import com.tydic.portal.service.PortalLoginService;
import com.tydic.system.domain.Account;
import com.tydic.system.domain.Company;
import com.tydic.system.domain.bo.QuerySysDictTypeBo;
import com.tydic.system.domain.bo.SysUserBo;
import com.tydic.system.domain.req.SeachUnwantedAuthSignRequest;
import com.tydic.system.domain.resp.UnwantedAuthSignStatusResponse;
import com.tydic.system.domain.vo.SysDictTypeVo;
import com.tydic.system.domain.vo.SysUserVo;
import com.tydic.system.service.IFddService;
import com.tydic.system.service.ISysDictTypeService;
import com.tydic.system.service.ISysUserService;
import com.tydic.system.utils.PasswordUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.Duration;

/**
 * 管理端登录
 */
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/portal")
public class PortalUserController extends BaseController {

    private final PortalLoginService portalLoginService;

    private final ISysUserService sysUserService;

    private final IBordererInfoService bordererInfoService;

    private final ISysDictTypeService dictTypeService;

    private final IFddService fddService;

    private final IEnterpriseService enterpriseService;

    private final IMutualHelpOrganizationService mutualHelpOrganizationService;


    /**
     * 登录
     *
     * @param bo
     * @return
     */
    @SaIgnore
    @PostMapping("/user/login")
    public R<PortalLoginVo> login(@Validated({EditGroup.class}) @RequestBody PortalLoginBo bo, HttpServletRequest request) {
        String username = bo.getUsername();
        String password = bo.getPassword();
        String imageCode = bo.getImageCode();
        SysUserVo user = sysUserService.selectByLoginCode(username);
        if (user == null) {
            throw new ServiceException("登录账号不存在");
        }
        validateCaptcha(username, imageCode);
        portalLoginService.checkLogin(LoginType.PASSWORD, username, () -> !PasswordUtils.match(password, user.getPassword()));
        LoginUser loginUser = portalLoginService.buildLoginUser(user);
        SaLoginModel model = new SaLoginModel();
        model.setDevice("PC");
        model.setTimeout(Duration.ofHours(30).toMillis());
        model.setIsLastingCookie(true);
        model.setIsWriteHeader(true);
        LoginHelper.login(loginUser, model);
        PortalLoginVo portalLoginVo = BeanUtil.toBean(loginUser, PortalLoginVo.class);
        String userCertificationStatus = UserCertificationStatusEnum.READY.getStatus();
        String enterpriseCertificationStatus = EnterpriseCertificationStatusEnum.READY.getStatus();
        LoginUser currentUser = LoginHelper.getLoginUser();
        if (currentUser.isBordererAgent() || currentUser.isBorderer() || currentUser.isEnterpriseAdmin()) {
            //边民/边民代表
            if (currentUser.isBorderer() || currentUser.isBordererAgent()) {
                BordererInfo bordererInfo = bordererInfoService.getBordererInfoByUserCode(currentUser.getUserCode());
                if (bordererInfo != null) {
                    userCertificationStatus = bordererInfo.getUserCertificationStatus();
                    enterpriseCertificationStatus = bordererInfo.getEnterpriseCertificationStatus();
                    portalLoginVo.setAuditStatus(bordererInfo.getAuditStatus());
                    portalLoginVo.setUserName(bordererInfo.getName());
                }
            } else {//企业
                Enterprise enterprise = enterpriseService.getEnterpriseByUserCode(currentUser.getUserCode());
                if (enterprise != null) {
                    userCertificationStatus = enterprise.getUserCertificationStatus();
                    enterpriseCertificationStatus = enterprise.getEnterpriseCertificationStatus();
                    portalLoginVo.setAuditStatus(enterprise.getAuditStatus());
                    portalLoginVo.setUserName(enterprise.getEnterpriseName());
                }
            }
        } else {
            userCertificationStatus = UserCertificationStatusEnum.SUCCESS.getStatus();
            enterpriseCertificationStatus = UserCertificationStatusEnum.SUCCESS.getStatus();
            portalLoginVo.setAuditStatus(AuditStatusEnum.SUCCESS.getStatus());
        }
        portalLoginVo.setUserCertificationStatus(userCertificationStatus);
        portalLoginVo.setEnterpriseCertificationStatus(enterpriseCertificationStatus);
        if (StringUtils.isBlank(portalLoginVo.getUserName())) {
            portalLoginVo.setUserName(loginUser.getLoginCode());
        }
        return R.ok(portalLoginVo);
    }

    /**
     * 退出登录
     *
     * @return
     */
    @SaIgnore
    @GetMapping(value = "/user/loginOut")
    public R<Void> loginOut() {
        portalLoginService.logout();
        return R.ok("退出成功");
    }

    /**
     * 校验验证码
     *
     * @param username  用户名
     * @param imageCode 图片验证码
     */
    private void validateCaptcha(String username, String imageCode) {
        String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + imageCode.toLowerCase();
        String captcha = RedisUtils.getCacheObject(verifyKey);
        RedisUtils.deleteObject(verifyKey);
        if (captcha == null) {
            portalLoginService.recordLoginInfo(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
            throw new CaptchaExpireException();
        }
        if (!imageCode.equalsIgnoreCase(captcha)) {
            portalLoginService.recordLoginInfo(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
            throw new CaptchaException();
        }
    }

    private void checkSmsCode(String photoNumber, String smsCode) {
        String key = GlobalConstants.CAPTCHA_CODE_KEY + photoNumber;
        String code = RedisUtils.getCacheObject(key);
        if (CharSequenceUtil.equals(smsCode, "999999")) {
            return;
        }
        if (!StringUtils.equals(smsCode, code)) {
            throw new ServiceException("短信验证码错误");
        }
    }

    /**
     * 注册
     *
     * @param bo
     * @return
     */
    @SaIgnore
    @PostMapping("/user/register")
    public R<Void> register(@Validated(AddGroup.class) RegisterUserBo bo) {
        if (!bo.getPassword().equals(bo.getConfirmPassword())) {
            return R.fail("请检查密码是否一致!");
        }
        // 判断用户号码是否已注册
        if (sysUserService.existsByLoginCode(bo.getMobile())) {
            return R.fail("该手机号码已被注册!");
        }
        validateCaptcha(bo.getMobile(), bo.getImageCode());
        checkSmsCode(bo.getMobile(), bo.getPhoneCode());
        SysUserBo registerUser = new SysUserBo();
        registerUser.setLoginCode(bo.getMobile());
        registerUser.setUserType(bo.getUserType());
        registerUser.setPhone(bo.getMobile());
        registerUser.setMobile(bo.getMobile());
        registerUser.setPassword(PasswordUtils.encryptPassword(bo.getPassword()));
        Account account = fddService.getAccountByMobile(bo.getMobile());
        if (account == null && CharSequenceUtil.isNotBlank(registerUser.getUserName())) {
            account = new Account();
            account.setMobile(registerUser.getMobile());
            account.setUserName(registerUser.getUserName());
            fddService.createAccount(account);
        }
        boolean result = sysUserService.insertByBo(registerUser);
        return toAjax(result);
    }

    /**
     * 忘记密码
     *
     * @param bo
     * @return
     */
    @SaIgnore
    @PostMapping("/user/forgotPassword")
    public R<Void> forgetPassword(@Validated(EditGroup.class) ForgetPasswordBo bo) {
        if (!bo.getPassword().equals(bo.getConfirmPassword())) {
            return R.fail("请检查密码是否一致!");
        }
        if (!sysUserService.existsByLoginCode(bo.getMobile())) {
            throw new ServiceException("该手机号码未注册");
        }
        validateCaptcha(bo.getMobile(), bo.getImageCode());
        checkSmsCode(bo.getMobile(), bo.getPhoneCode());
        boolean result = sysUserService.changePassword(bo.getMobile(), BCrypt.hashpw(bo.getPassword()));
        return toAjax(result);
    }

    /**
     * 获取边民信息
     *
     * @param id 边民id
     * @return
     */
    @GetMapping("/border/getBordererInfo")
    public R<BordererInfoVo> getBordererInfoById() {
        String userCode = LoginHelper.getLoginUser().getUserCode();
        return R.ok(bordererInfoService.selectByUserCode(userCode));
    }


    @GetMapping("/user/getUserDetail")
    public R<PortalLoginVo> getUserDetail() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        PortalLoginVo portalLoginVo = BeanUtil.toBean(loginUser, PortalLoginVo.class);
        String userCertificationStatus = UserCertificationStatusEnum.SUCCESS.getStatus();
        String enterpriseCertificationStatus = UserCertificationStatusEnum.SUCCESS.getStatus();
        String auditStatus = AuditStatusEnum.SUCCESS.getStatus();
        portalLoginVo.setUserCertificationStatus(userCertificationStatus);
        portalLoginVo.setEnterpriseCertificationStatus(enterpriseCertificationStatus);
        portalLoginVo.setAuditStatus(auditStatus);
        if (StringUtils.isBlank(portalLoginVo.getUserName())) {
            portalLoginVo.setUserName(loginUser.getLoginCode());
        }
        return R.ok(portalLoginVo);
    }

    /**
     * 分页查询数据字典列表
     *
     * @param bo
     * @return
     */
    @PostMapping("/dictionary/type/getDictTypeList")
    public R<TableDataInfo<SysDictTypeVo>> getDictTypeList(@Validated(QueryGroup.class) QuerySysDictTypeBo bo) {
        return R.ok(dictTypeService.queryPage(bo));
    }

    /**
     * 个人信息管理
     *
     * @return
     */
    @GetMapping(value = "/user/manageUserInfo")
    public R manageUserInfo() {
        ManageUserInfoResponse manageUserInfoResponse = new ManageUserInfoResponse();
        LoginUser currentUser = LoginHelper.getLoginUser();
        if (currentUser.isBorderer() || currentUser.isBordererAgent()) {
            BordererInfo bordererInfo = bordererInfoService.getBordererInfoByUserCode(currentUser.getUserCode());
            Account account = fddService.getAccountByMobile(CharSequenceUtil.blankToDefault(currentUser.getMobile(), currentUser.getPhone()));
            SeachUnwantedAuthSignRequest seachUnwantedAuthSignRequest = new SeachUnwantedAuthSignRequest();
            seachUnwantedAuthSignRequest.setAuthorizerFlag(AuthTypeEnum.BORDERER.getType());
            seachUnwantedAuthSignRequest.setAuthorizerTargetId(account.getAccountId());
            UnwantedAuthSignStatusResponse response = fddService.searchUnwantedAuthSignStatus(seachUnwantedAuthSignRequest);
            if (NumberUtil.equals(response.getStatus(), UnwantedAuthSignEnum.EFFECT.getType())) {
                bordererInfo.setOpenAuthSignStatus(EnableEnum.ENABLE.getStatus());
            } else {
                bordererInfo.setOpenAuthSignStatus(EnableEnum.DISABLE.getStatus());
            }
            bordererInfoService.update(bordererInfo);
            manageUserInfoResponse.setBordererInfo(bordererInfo);
        } else if (currentUser.isEnterpriseAdmin()) {
            Enterprise enterprise = enterpriseService.getEnterpriseByUserCode(currentUser.getUserCode());
            Company company = fddService.getCompanyByCompanyName(enterprise.getEnterpriseName());
            SeachUnwantedAuthSignRequest seachUnwantedAuthSignRequest = new SeachUnwantedAuthSignRequest();
            seachUnwantedAuthSignRequest.setAuthorizerFlag(AuthTypeEnum.ENTERPRISE.getType());
            seachUnwantedAuthSignRequest.setAuthorizerTargetId(company.getCompanyId());
            UnwantedAuthSignStatusResponse response = fddService.searchUnwantedAuthSignStatus(seachUnwantedAuthSignRequest);
            if (NumberUtil.equals(response.getStatus(), UnwantedAuthSignEnum.EFFECT.getType())) {
                enterprise.setOpenAuthSignStatus(EnableEnum.ENABLE.getStatus());
            } else {
                enterprise.setOpenAuthSignStatus(EnableEnum.DISABLE.getStatus());
            }
            enterpriseService.update(enterprise);
            manageUserInfoResponse.setEnterprise(enterprise);
        }
        manageUserInfoResponse.setUserType(currentUser.getUserType());
        manageUserInfoResponse.setUserCode(currentUser.getUserCode());
        manageUserInfoResponse.setUserName(currentUser.getUserName());
        manageUserInfoResponse.setLoginCode(currentUser.getLoginCode());
        return R.ok(manageUserInfoResponse);
    }

    /**
     * 通过身份证获取边民信息
     *
     * @param idCardNumber
     * @return
     */
    @GetMapping("/user/getBordererInfo")
    public R<MutualHelpOrganizationMemberVo> getBordererInfo(@NotBlank(message = "请传入身份证号码") String idCardNumber) {
        return R.ok(mutualHelpOrganizationService.getByIdCardNumber(idCardNumber));
    }
}
